package com.app.web.user.info;

import com.alibaba.fastjson.JSON;
import com.app.base.EnumType;
import com.app.utils.base.j2se.*;
import com.app.utils.redis.KeyParam;
import com.app.utils.redis.Redis;
import com.app.utils.spring.config.SystemError;
import com.app.utils.spring.properties.Config;
import com.app.utils.web.Param;
import com.app.web.user.team.TeamService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Description
 * Created by 王伟
 * Date create on 14:26 2019/11/19.
 */
@Service
public class UserInfoService {

    @Autowired
    private UserInfoDao userInfoDao;
    @Autowired
    private TeamService teamModel;
    /**
     * 未找到用户ID
     **/
    private final String unFindUserId = "-1";
    /**
     * 用户缓存过期时间3天
     */
    private final int userInfoTimeOut = 30 * 60 * 60;
    /**
     * 用户推荐码缓存过期时间2天
     */
    private final int userMcodeTimeOut = 30 * 60 * 60;
    /**
     * 多客员角色编号
     **/
    private final int ROLE_MEMBER = 3;

    /**
     * 通过用户ID获取用户信息
     *
     * @param userId 用户id
     * @return 用户信息
     */
    @SuppressWarnings("rawtypes")
    public UserInfo info(long userId) {
        //缓存中用户信息没有失效 直接返回
        String userKey = KeyParam.userInfoByUid(userId);
        Map userCache = Redis.hash.hgetall(userKey);
        if (Common.isNotEmpty(userCache) && Common.isNotEmpty(userCache.get("uid")) &&
                Common.isNotEmpty(userCache.get("sub_node")) && Common.isNotEmpty(userCache.get("old_sub_node"))) {
            return JsonUtil.mapToBean(userCache, UserInfo.class);
        }
        return refreshCache(userId);
    }

    /**
     * 刷新用户缓存信息
     *
     * @param userId 用户id
     * @return
     */
    public UserInfo refreshCache(long userId) {
        //获取用户信息,刷新缓存信息
        UserInfo userInfo = userInfoDao.infoByUserId(userId);
        if (null == userInfo) {
            userInfo = new UserInfo();
            userInfo.setRole(0);
            userInfo.setUid(userId);
        }
        //将用户信息缓存到redis
        infoToCache(userInfo);
        return userInfo;
    }

    /**
     * 缓存用户信息
     */
    private void infoToCache(UserInfo userInfo) {
        String userKey = KeyParam.userInfoByUid(userInfo.getUid());
        Map<String, Object> initCache = JsonUtil.beanToMap(userInfo);
        //取消缓存 注册ip信息
        initCache.remove("reg_ip");
        Redis.hash.hmset(userKey, MapHandler.obj2StrNotNull(initCache),userInfoTimeOut);
    }

    /**
     * 功能：根据推荐码获取用户信息
     *
     * @param mcode 推荐码
     * @return 用户信息
     */
    public UserInfo infoByMcode(int mcode) {
        //根据推荐码 获取用户id
        String userMcodeKey = KeyParam.userIdByMcode(mcode);
        String userId = Redis.str.get(userMcodeKey);

        //邀请码不存在
        if (unFindUserId.equals(userId)) {
//            SystemError.wrapBs("8004", ConfigInfo.pp.get("8004"));
            return null;
        }
        //存在用户ID映射关系 通过用户ID查询用户信息
        if (StringHandler.getLong(userId) > 0) {
            return info(Convert.objToInt(userId));
        }
        //不存在映射关系 去数据库查询 没有存个-1标识
        UserInfo userInfo = userInfoDao.infoByMcode(mcode);
        if (userInfo == null) {
            Redis.str.set(userMcodeKey,"-1",userMcodeTimeOut);
//            SystemError.wrapBs("8004", ConfigInfo.pp.get("8004"));
            return null;
        }
        //根据推荐码获取用户信息
        Redis.str.set(userMcodeKey,userInfo.getUid(),userMcodeTimeOut);
        return userInfo;
    }

    /**
     * 功能：注册用户信息
     *
     * @param userId      用户id
     * @param pcode       推荐码
     * @param duoKeUserIp 注册用户ip
     * @return
     */
    public UserInfo addInfo(int userId, int pcode, String duoKeUserIp) {
        //效验户是否已经注册
        UserInfo userInfo = info(userId);
        if (userInfo.getMcode() > 0) {
            return userInfo;
        }
        //效验推荐码的有有效性
        userInfo = userInfoDao.infoByMcode(pcode);
        if (Common.isEmpty(userInfo)) {
            SystemError.wrapBs("6001","请填写正确的邀请码");
        }
        infoToCache(userInfo);
        //组装用户信息
        UserInfo addUserInfo = new UserInfo();
        addUserInfo.setRole(EnumType.ROLE.普通用户.getRole());//角色
        addUserInfo.setUid(userId);//用户ID
        addUserInfo.setPcode(pcode);//父级推广码
        addUserInfo.setMcode(userInfoDao.getMcode());//获取用户推荐码
        addUserInfo.setInit_pcode(pcode);//初始化父级推广码
        addUserInfo.setReg_time(new Date());//注册时间
        addUserInfo.setSub_node(userInfo.getSub_node() + "-" + addUserInfo.getMcode());//子节点
        addUserInfo.setOld_sub_node(userInfo.getOld_sub_node() + "-" + addUserInfo.getMcode());
        try {
            //注册用户信息
            if (userInfoDao.addInfo(addUserInfo) <= 0) {
                SystemError.wrapBs("6001","用户信息注册失败");
            }
        } catch (Exception e) {
            //TODO 主键冲突
//            if (!Common.mySQLPKConflict(e)) {
//                throw e;
//            }
            addUserInfo = userInfoDao.infoByUserId(userId);
        }

        //将用户信息缓存到redis 和更新 mcode与用户关系
        String userKey = KeyParam.userInfoByUid(userId);
        Map<String, Object> initCache = JsonUtil.beanToMap(addUserInfo);
        Redis.hash.hmset(userKey,MapHandler.obj2StrNotNull(initCache),userInfoTimeOut);
        Redis.str.set(KeyParam.userIdByMcode(addUserInfo.getMcode()),userId,userMcodeTimeOut);
        return addUserInfo;
    }


    /**
     * 功能：升级用户
     *
     */
    @Transactional
    public void upLevel(int role, String openid) {
        UserInfo userInfo = userInfoDao.infoByOpenid(openid);
        //用户信息验证
        if(Common.isEmpty(userInfo)){
            System.out.println("获取用户信息失败,openid:"+openid);
            return;
        }
        //用户升级角色验证
        if(role<=userInfo.getRole()){
            System.out.println("用户:"+userInfo.getMcode()+"当前角色为:"+Param.getRoleName(userInfo.getRole())+",无法升级到:"+Param.getRoleName(role));
            return;
        }
        long userRegTime = userInfo.getReg_time().getTime();
        long nowTime = System.currentTimeMillis();
        long regTime = Convert.strToLong(Config.pp.get("pull.new.time"),0);
        //把当前用户赋值为查询上级模型,便于递归
        UserInfo bonusInfo = userInfo;
        try {
            //验证用户是否是普通用户 并且注册时间符合奖励
            if(userInfo.getRole()==0 && (regTime==0 || nowTime-userRegTime<regTime)){
                List<Map<String,Object>> bonusList = new ArrayList<>();
                if(role==1){
                    UserInfo pcodeBonusInfo = userInfoDao.infoByMcode(bonusInfo.getPcode());
                    if(Common.isNotEmpty(pcodeBonusInfo)){
                        Map<String,Object> map = new HashMap<>();
                        map.put("uid",pcodeBonusInfo.getUid());
                        //组装详情数据
                        long money = Convert.strToLong(Config.pp.get("user.up.bonus.role." + role), 0);
                        map.put("money",money);
                        bonusList.add(map);
                    }
                }else{
                    //获取总奖励金额
                    long bonus = Convert.strToLong(Config.pp.get("user.up.bonus.role."+role), 0);
                    //获取最大分层次数
                    long count = Convert.strToLong(Config.pp.get("user.up.bonus.count"), 0);
                    for(int i=1;i<count;i++){
                        //验证是否获取到分佣用户
                        UserInfo teacherInfo = userInfoDao.infoByMcode(bonusInfo.getPcode());
                        //如果上级不存在,就将当前用户赋值为老师去参与分成
                        if(Common.isEmpty(teacherInfo)){
                            //重新声明stream处理中需要的变量
                            long bonusInfoUid = bonusInfo.getUid();
                            int k = i;
                            bonusList = bonusList.stream().peek(x->{
                                int uid = Convert.objToInt(x.get("uid"));
                                if(uid == bonusInfoUid){
                                    long level = Convert.strToLong(Config.pp.get("user.up.bonus.level."+k), 0);
                                    x.put("money",Convert.objToInt(x.get("money"))+(bonus*level/100));
                                    x.put("rate",Convert.objToInt(x.get("rate"))+level);
                                }
                            }).collect(Collectors.toList());
                        }else{
                            //赋值下一次要查询上级的用户信息
                            bonusInfo = teacherInfo;
                            //组装收益信息
                            Map<String,Object> map = new HashMap<>();
                            map.put("uid",teacherInfo.getUid());
                            long level = Convert.strToLong(Config.pp.get("user.up.bonus.level."+i), 0);
                            map.put("money",bonus*level/100);
                            map.put("rate",level);
                            bonusList.add(map);
                        }
                    }
                }
                //增加用户可提现余额
                if(Common.isNotEmpty(bonusList) && 0<bonusList.size()){
                    bonusList = bonusList.stream().peek(x->{
                        //组装明细信息
                        x.put("type",2);
                        x.put("inorout",1);
                        x.put("remark","拉新用户mcode:"+userInfo.getMcode()+"升级到"+ Param.getRoleName(role) +"的奖励金额,分成占比:"+x.get("rate")+"%");
                    }).collect(Collectors.toList());
                    //记录金额明细
                    userInfoDao.addMoneyDetail(bonusList);
                    //修改用户余额
                    userInfoDao.addMoney(bonusList);
                }
            }
            //升级用户
            userInfoDao.userUpLevel(role, userInfo.getUid());
        } catch (Exception e) {
            //TODO 主键冲突
//            if (!Common.mySQLPKConflict(e)) {
                throw e;
//            }
        }
        //更新缓存信息
        String userKey = KeyParam.userInfoByUid(userInfo.getUid());
        Map<String,String> map = new HashMap<String,String>(){{
            put("role", String.valueOf(role));
            put("up_time",DateHandler.getDateString(new Date()));
        }};
        Redis.hash.hmset(userKey,map,userInfoTimeOut);
    }

    /**
     * 保存用户小程序码
     * @param map uid type appId imgName
     * @return
     */
    public void saveUserShareImg(Map map){
        userInfoDao.saveUserShareImg(map);
    }

    /**
     * 获取用户小程序码
     * @param map uid type appId
     * @return
     */
    public String getUserShareImg(Map map){
        return userInfoDao.getUserShareImg(map);
    }

}
